﻿using System;
using System.Windows;
using System.Windows.Input;
using System.Diagnostics;

namespace WickedFlame.GenDock
{
    public class DockableWindow : Window, IContentContainer, IDisposable
    {
        public event EventHandler CollapseChanged;

        FrameworkElement _dragEnabledArea;
        static object syncRoot = new object();

        static DockableWindow()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DockableWindow), new FrameworkPropertyMetadata(typeof(DockableWindow)));
        }

        public DockableWindow()
            : base()
        {
            this.SizeChanged += new SizeChangedEventHandler(OnSizeChanged);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _dragEnabledArea = GetTemplateChild("dragableHeader") as FrameworkElement;

            if (_dragEnabledArea != null)
            {
                _dragEnabledArea.MouseLeftButtonDown += new MouseButtonEventHandler(OnDragMouseDown);
                _dragEnabledArea.MouseMove += new MouseEventHandler(OnDragMouseMove);

                this.LocationChanged += new EventHandler(OnWindowMoved);
            }
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);

            this.CommandBindings.Add(
                new CommandBinding(CollapseCommand, this.OnExecuteCommand, this.OnCanExecuteCommand));
            this.CommandBindings.Add(
                new CommandBinding(HideCommand, this.OnExecuteCommand, this.OnCanExecuteCommand));
            this.CommandBindings.Add(
                new CommandBinding(CloseCommand, this.OnExecuteCommand, this.OnCanExecuteCommand));
        }

        private void OnSizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (CollapseChanged != null)
                CollapseChanged(this, new EventArgs());
        }

        internal bool IsCollapsed
        {
            get
            {
                return (bool)GetValue(IsCollapsedProperty);
            }
            set
            {
                SetValue(IsCollapsedProperty, value);
            }
        }

        public static readonly DependencyProperty IsCollapsedProperty =
            DependencyProperty.Register("IsCollapsed", typeof(bool), typeof(DockableWindow), new PropertyMetadata(false));

        internal bool IsTranslucent
        {
            get
            {
                return (bool)GetValue(IsTranslucentProperty);
            }
            set
            {
                if (IsTranslucentAllowed)
                    SetValue(IsTranslucentProperty, value);
            }
        }

        public static readonly DependencyProperty IsTranslucentProperty =
            DependencyProperty.Register("IsTranslucent", typeof(bool), typeof(DockableWindow), new PropertyMetadata(false));

        internal bool IsTranslucentAllowed
        {
            get
            {
                return (bool)GetValue(IsTranslucentAllowedProperty);
            }
            set
            {
                SetValue(IsTranslucentAllowedProperty, value);
            }
        }

        public static readonly DependencyProperty IsTranslucentAllowedProperty =
            DependencyProperty.Register("IsTranslucentAllowed", typeof(bool), typeof(DockableWindow), new PropertyMetadata(false));

        private static RoutedUICommand hideCommand = null;
        public static RoutedUICommand HideCommand
        {
            get
            {
                lock (syncRoot)
                {
                    if (null == hideCommand)
                    {
                        hideCommand = new RoutedUICommand("H_ide", "Hide", typeof(ContentDocument));
                    }
                }
                return hideCommand;
            }
        }

        private static RoutedUICommand closeCommand = null;
        public static RoutedUICommand CloseCommand
        {
            get
            {
                lock (syncRoot)
                {
                    if (null == closeCommand)
                    {
                        closeCommand = new RoutedUICommand("C_lose", "Close", typeof(DockableWindow));
                    }
                }
                return closeCommand;
            }
        }

        private static RoutedUICommand collapseCommand = null;
        public static RoutedUICommand CollapseCommand
        {
            get
            {
                lock (syncRoot)
                {
                    if (null == collapseCommand)
                    {
                        collapseCommand = new RoutedUICommand("Co_llapse", "Collapse", typeof(DockableWindow));
                    }
                }
                return collapseCommand;
            }
        }

        internal virtual void OnExecuteCommand(object sender, ExecutedRoutedEventArgs e)
        {
            if (!e.Handled && e.Command == HideCommand)
            {
                //Manager.Hide(this);

                e.Handled = true;
                
                this.Close();
            }
            else if (!e.Handled && e.Command == CloseCommand)
            {
                e.Handled = true;
                this.Close();
            }
            else if (!e.Handled && e.Command == CollapseCommand)
            {
                if (IsCollapsed)
                {
                    IsCollapsed = false;
                }
                else
                {
                    if (double.IsNaN(_dragEnabledArea.Width) || _dragEnabledArea.Width == 0)
                        _dragEnabledArea.Width = (Content as ContentDocument).Width;
                    IsCollapsed = true;
                }
                //if (CollapseChanged != null)
                //    CollapseChanged(this, new EventArgs());
            }
        }

        protected virtual void OnCanExecuteCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        protected override void OnClosed(EventArgs e)
        {
            Dispose();
            base.OnClosed(e);
        }

        #region Drag & Drop Management

        //Point ptStartDrag;
        bool isMouseDown = false;

        protected bool IsMouseDown
        {
            get
            {
                return isMouseDown;
            }
        }

        internal bool IsDocked
        {
            get
            {
                return (bool)GetValue(IsDockedProperty);
            }
            set
            {
                SetValue(IsDockedProperty, value);

                if (value)
                {
                    IsTranslucent = false;
                    IsTranslucentAllowed = false;
                }
                else
                {
                    IsTranslucentAllowed = true;
                    if (!IsMouseOver)
                        IsTranslucent = true;
                }
            }
        }

        public static readonly DependencyProperty IsDockedProperty =
            DependencyProperty.Register("IsDocked", typeof(bool), typeof(DockableWindow),new PropertyMetadata(true));

        void OnDragMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (!e.Handled)
            {
                isMouseDown = true;

                (Content as ContentDocument).ManagerService.OnDragStart(this);
                
                //Drag window
                this.DragMove();
            }
        }

        void OnDragMouseMove(object sender, MouseEventArgs e)
        {
            //mouse move event and isMouseDown can only occure just after the drag of the window
            if (isMouseDown)
            {
                Point p = Mouse.GetPosition((IInputElement)this.Owner);
                (Content as ContentDocument).ManagerService.OnDrop(this, p);
                isMouseDown = false;
            }
        }

        void OnWindowMoved(object sender, EventArgs e)
        {
            if (isMouseDown)
            {
                if (IsDocked)
                {
                    //release window at the first moment when mouse is down and window is moved
                    (Content as ContentDocument).ManagerService.ReleaseDockedWindow(this);
                    IsDocked = false;
                }
            }
        }

        protected override void OnMouseEnter(MouseEventArgs e)
        {
            base.OnMouseEnter(e);

            if (IsMouseOver)
                IsTranslucent = false;
        }

        protected override void OnMouseLeave(MouseEventArgs e)
        {
            base.OnMouseLeave(e);

            IsTranslucent = true;
        }

        #endregion

        #region IDockeableContentContainer Members

        public void AddContent(ContentDocument content)
        {
            this.Content = content;
        }

        public void RemoveContent(ContentDocument content)
        {
            this.Content = null;
        }

        public bool ShowContent(Type type)
        {
            Type t = this.Content.GetType();
            if (t == type)
            {
                IsCollapsed = false;
                return true;
            }

            return false;
        }

        public bool ShowContent(ContentDocument content)
        {
            if (this.Content == content)
            {
                IsCollapsed = false;
                return true;
            }

            return false;
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            RemoveContent(this.Content as ContentDocument);
        }

        #endregion
    }
}
